{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Machine Learning for Design"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "## Notebook for Session06: Advanced Features - Model Selection"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "Welcome to pylab, a matplotlib-based Python environment [backend: module://IPython.zmq.pylab.backend_inline].\n",
      "For more information, type 'help(pylab)'.\n"
     ]
    }
   ],
   "source": [
    "%pylab inline"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from sklearn.datasets import fetch_20newsgroups\n",
    "\n",
    "news = fetch_20newsgroups(subset='all')\n",
    "\n",
    "n_samples = 3000\n",
    "\n",
    "X = news.data[:n_samples]\n",
    "y = news.target[:n_samples]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from sklearn.naive_bayes import MultinomialNB\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.feature_extraction.text import TfidfVectorizer"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def get_stop_words():\n",
    "    result = set()\n",
    "    for line in open('stopwords_en.txt', 'r').readlines():\n",
    "        result.add(line.strip())\n",
    "    return result\n",
    "\n",
    "stop_words = get_stop_words()\n",
    "\n",
    "clf = Pipeline([\n",
    "    ('vect', TfidfVectorizer(\n",
    "                stop_words=stop_words,\n",
    "                token_pattern=ur\"\\b[a-z0-9_\\-\\.]+[a-z][a-z0-9_\\-\\.]+\\b\",         \n",
    "    )),\n",
    "    ('nb', MultinomialNB(alpha=0.01)),\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from sklearn.cross_validation import cross_val_score, KFold\n",
    "from scipy.stats import sem\n",
    "\n",
    "def evaluate_cross_validation(clf, X, y, K):\n",
    "    # create a k-fold croos validation iterator of k=5 folds\n",
    "    cv = KFold(len(y), K, shuffle=True, random_state=0)\n",
    "    # by default the score used is the one returned by score method of the estimator (accuracy)\n",
    "    scores = cross_val_score(clf, X, y, cv=cv)\n",
    "    print scores\n",
    "    print (\"Mean score: {0:.3f} (+/-{1:.3f})\").format(\n",
    "        np.mean(scores), sem(scores))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[ 0.812  0.808  0.822]\n",
      "Mean score: 0.814 (+/-0.004)\n"
     ]
    }
   ],
   "source": [
    "evaluate_cross_validation(clf, X, y, 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def calc_params(X, y, clf, param_values, param_name, K):\n",
    "    # initialize training and testing scores with zeros\n",
    "    train_scores = np.zeros(len(param_values))\n",
    "    test_scores = np.zeros(len(param_values))\n",
    "    \n",
    "    # iterate over the different parameter values\n",
    "    for i, param_value in enumerate(param_values):\n",
    "        print param_name, ' = ', param_value\n",
    "        \n",
    "        # set classifier parameters\n",
    "        clf.set_params(**{param_name:param_value})\n",
    "        \n",
    "        # initialize the K scores obtained for each fold\n",
    "        k_train_scores = np.zeros(K)\n",
    "        k_test_scores = np.zeros(K)\n",
    "        \n",
    "        # create KFold cross validation\n",
    "        cv = KFold(n_samples, K, shuffle=True, random_state=0)\n",
    "        \n",
    "        # iterate over the K folds\n",
    "        for j, (train, test) in enumerate(cv):\n",
    "            # fit the classifier in the corresponding fold\n",
    "            # and obtain the corresponding accuracy scores on train and test sets\n",
    "            clf.fit([X[k] for k in train], y[train])\n",
    "            k_train_scores[j] = clf.score([X[k] for k in train], y[train])\n",
    "            k_test_scores[j] = clf.score([X[k] for k in test], y[test])\n",
    "            \n",
    "        # store the mean of the K fold scores\n",
    "        train_scores[i] = np.mean(k_train_scores)\n",
    "        test_scores[i] = np.mean(k_test_scores)\n",
    "       \n",
    "    # plot the training and testing scores in a log scale\n",
    "    plt.semilogx(param_values, train_scores, alpha=0.4, lw=2, c='b')\n",
    "    plt.semilogx(param_values, test_scores, alpha=0.4, lw=2, c='g')\n",
    "    \n",
    "    plt.xlabel(param_name + \" values\")\n",
    "    plt.ylabel(\"Mean cross validation accuracy\")\n",
    "\n",
    "    # return the training and testing scores on each parameter value\n",
    "    return train_scores, test_scores"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[  1.00000000e-07   1.00000000e-06   1.00000000e-05   1.00000000e-04\n",
      "   1.00000000e-03   1.00000000e-02   1.00000000e-01   1.00000000e+00]\n"
     ]
    }
   ],
   "source": [
    "alphas = np.logspace(-7, 0, 8)\n",
    "print alphas"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "nb__alpha  =  1e-07\n",
      "nb__alpha  =  1e-06\n",
      "nb__alpha  =  1e-05\n",
      "nb__alpha  =  0.0001\n",
      "nb__alpha  =  0.001\n",
      "nb__alpha  =  0.01\n",
      "nb__alpha  =  0.1\n",
      "nb__alpha  =  1.0\n"
     ]
    },
    {
     "data": {
      "image/png": "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\nBgcREUny/wH2KqB3IEgzAAAAAElFTkSuQmCC\n"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "train_scores, test_scores = calc_params(X, y, clf, alphas, 'nb__alpha', 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "training scores:  [ 1.          1.          1.          1.          1.          1.\n",
      "  0.99683333  0.97416667]\n",
      "testing scores:  [ 0.77133333  0.77666667  0.78233333  0.79433333  0.80333333  0.814\n",
      "  0.80733333  0.74533333]\n"
     ]
    }
   ],
   "source": [
    "print 'training scores: ', train_scores\n",
    "print 'testing scores: ', test_scores"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from sklearn.svm import SVC\n",
    "\n",
    "clf = Pipeline([\n",
    "    ('vect', TfidfVectorizer(\n",
    "                stop_words=stop_words,\n",
    "                token_pattern=ur\"\\b[a-z0-9_\\-\\.]+[a-z][a-z0-9_\\-\\.]+\\b\",         \n",
    "    )),\n",
    "    ('svc', SVC()),\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "svc__gamma  =  0.01\n",
      "svc__gamma  =  0.1\n",
      "svc__gamma  =  1.0\n",
      "svc__gamma  =  10.0\n"
     ]
    },
    {
     "data": {
      "image/png": "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\n"
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "gammas = np.logspace(-2, 1, 4)\n",
    "\n",
    "train_scores, test_scores = calc_params(X, y, clf, gammas, 'svc__gamma', 3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "training scores:  [ 0.06183333  0.279       0.99966667  1.        ]\n",
      "testing scores:  [ 0.04866667  0.162       0.74666667  0.05166667]\n"
     ]
    }
   ],
   "source": [
    "print 'training scores: ', train_scores\n",
    "print 'testing scores: ', test_scores"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "For gamma < 1 we have underfitting. For gamma > 1 we have overfitting. So here, the best result is for gamma = 1 where we obtain a training an accuracy of 0.999 and a testing accuracy of 0.760"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from sklearn.grid_search import GridSearchCV\n",
    "\n",
    "parameters = {\n",
    "    'svc__gamma': np.logspace(-2, 1, 4),\n",
    "    'svc__C': np.logspace(-1, 1, 3),\n",
    "}\n",
    "\n",
    "clf = Pipeline([\n",
    "    ('vect', TfidfVectorizer(\n",
    "                stop_words=stop_words,\n",
    "                token_pattern=ur\"\\b[a-z0-9_\\-\\.]+[a-z][a-z0-9_\\-\\.]+\\b\",         \n",
    "    )),\n",
    "    ('svc', SVC()),\n",
    "])\n",
    "\n",
    "gs = GridSearchCV(clf, parameters, verbose=2, refit=False, cv=3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Fitting 3 folds for each of 12 candidates, totalling 36 fits\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=0.1 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.01, svc__C=0.1 -   8.7s\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=0.1 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.01, svc__C=0.1 -   8.6s\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=0.1 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.01, svc__C=0.1 -   8.7s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=0.1 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=0.1, svc__C=0.1 -   8.7s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=0.1 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=0.1, svc__C=0.1 -   8.8s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=0.1 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=0.1, svc__C=0.1 -   8.5s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=0.1 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=1.0, svc__C=0.1 -   8.8s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=0.1 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=1.0, svc__C=0.1 -   8.7s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=0.1 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=1.0, svc__C=0.1 -   8.8s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=0.1 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=10.0, svc__C=0.1 -   9.0s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=0.1 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=10.0, svc__C=0.1 -   9.0s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=0.1 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=10.0, svc__C=0.1 -   8.9s\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=1.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.01, svc__C=1.0 -   8.8s\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=1.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.01, svc__C=1.0 -   8.6s\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=1.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.01, svc__C=1.0 -   8.6s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=1.0 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=0.1, svc__C=1.0 -   8.7s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=1.0 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=0.1, svc__C=1.0 -   9.0s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=1.0 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=0.1, svc__C=1.0 -   8.5s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=1.0 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=1.0, svc__C=1.0 -   9.0s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=1.0 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=1.0, svc__C=1.0 -   9.0s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=1.0 ......................................\n",
      "[GridSearchCV] ............................. svc__gamma=1.0, svc__C=1.0 -   8.9s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=1.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=10.0, svc__C=1.0 -   9.4s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=1.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=10.0, svc__C=1.0 -   8.9s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=1.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=10.0, svc__C=1.0 -   8.7s\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=10.0 ....................................\n",
      "[GridSearchCV] ........................... svc__gamma=0.01, svc__C=10.0 -   8.7s\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=10.0 ....................................\n",
      "[GridSearchCV] ........................... svc__gamma=0.01, svc__C=10.0 -   8.6s\n",
      "[GridSearchCV] svc__gamma=0.01, svc__C=10.0 ....................................\n",
      "[GridSearchCV] ........................... svc__gamma=0.01, svc__C=10.0 -   8.4s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=10.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.1, svc__C=10.0 -   8.8s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=10.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.1, svc__C=10.0 -   8.7s\n",
      "[GridSearchCV] svc__gamma=0.1, svc__C=10.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=0.1, svc__C=10.0 -   8.5s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=10.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=1.0, svc__C=10.0 -   9.0s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=10.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=1.0, svc__C=10.0 -   8.8s\n",
      "[GridSearchCV] svc__gamma=1.0, svc__C=10.0 .....................................\n",
      "[GridSearchCV] ............................ svc__gamma=1.0, svc__C=10.0 -   8.7s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=10.0 ....................................\n",
      "[GridSearchCV] ........................... svc__gamma=10.0, svc__C=10.0 -   9.1s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=10.0 ....................................\n",
      "[GridSearchCV] ........................... svc__gamma=10.0, svc__C=10.0 -   8.9s\n",
      "[GridSearchCV] svc__gamma=10.0, svc__C=10.0 ....................................\n",
      "[GridSearchCV] ........................... svc__gamma=10.0, svc__C=10.0 -   8.8s"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "[Parallel(n_jobs=1)]: Done   1 jobs       | elapsed:    8.7s\n",
      "[Parallel(n_jobs=1)]: Done  36 out of  36 | elapsed:  5.3min finished\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "CPU times: user 315.62 s, sys: 0.44 s, total: 316.06 s\n",
      "Wall time: 316.89 s\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "({'svc__C': 10.0, 'svc__gamma': 0.10000000000000001}, 0.82799999999999996)"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "%time _ = gs.fit(X, y)\n",
    "\n",
    "gs.best_params_, gs.best_score_"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "With the grid search we obtained a better combination of C and gamma parameters, for values 10.0 and 0.10 respectively, we obtained a 3-fold cross validation accuracy of 0.828 much better than the best value we obtained (0.76) in the previous experiment by only adjusting gamma and keeeping C value at 1.0."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "We could continue trying to improve the results by also adjusting the vectorizer parameters in the grid search."
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "# Parallelizing"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "First we will declare a function that will persist all the K folds for the cross validation in different files. These files will be loaded by a process that will execute the corresponding fold:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from sklearn.externals import joblib\n",
    "from sklearn.cross_validation import ShuffleSplit\n",
    "import os\n",
    "\n",
    "def persist_cv_splits(X, y, K=3, name='data', suffix=\"_cv_%03d.pkl\"):\n",
    "    \"\"\"Dump K folds to filesystem.\"\"\"\n",
    "    \n",
    "    cv_split_filenames = []\n",
    "    \n",
    "    # create KFold cross validation\n",
    "    cv = KFold(n_samples, K, shuffle=True, random_state=0)\n",
    "    \n",
    "    # iterate over the K folds\n",
    "    for i, (train, test) in enumerate(cv):\n",
    "        cv_fold = ([X[k] for k in train], y[train], [X[k] for k in test], y[test])\n",
    "        cv_split_filename = name + suffix % i\n",
    "        cv_split_filename = os.path.abspath(cv_split_filename)\n",
    "        joblib.dump(cv_fold, cv_split_filename)\n",
    "        cv_split_filenames.append(cv_split_filename)\n",
    "    \n",
    "    return cv_split_filenames"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "cv_filenames = persist_cv_splits(X, y, name='news')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "The following function loads a particular fold and fits the classifier with the specified parameters set. Finally returns the testing score. This function will be called bye each of the parallel processes:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def compute_evaluation(cv_split_filename, clf, params):\n",
    "    \n",
    "    # All module imports should be executed in the worker namespace\n",
    "    from sklearn.externals import joblib\n",
    "\n",
    "    # load the fold training and testing partitions from the filesystem\n",
    "    X_train, y_train, X_test, y_test = joblib.load(\n",
    "        cv_split_filename, mmap_mode='c')\n",
    "    \n",
    "    clf.set_params(**params)\n",
    "    clf.fit(X_train, y_train)\n",
    "    test_score = clf.score(X_test, y_test)\n",
    "    return test_score"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "This function executes the grid search in parallel processes. For each of the parameter combination (returned by the IterGrid iterator), it iterates over the K folds and creates a process to compute the evaluation. It returns the parameter combinations alongside with the tasks list: "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "from sklearn.grid_search import IterGrid\n",
    "\n",
    "def parallel_grid_search(lb_view, clf, cv_split_filenames, param_grid):\n",
    "    \n",
    "    all_tasks = []\n",
    "    all_parameters = list(IterGrid(param_grid))\n",
    "    \n",
    "    # iterate over parameter combinations\n",
    "    for i, params in enumerate(all_parameters):\n",
    "        task_for_params = []\n",
    "        \n",
    "        # iterate over the K folds\n",
    "        for j, cv_split_filename in enumerate(cv_split_filenames):    \n",
    "            t = lb_view.apply(\n",
    "                compute_evaluation, cv_split_filename, clf, params)\n",
    "            task_for_params.append(t) \n",
    "        \n",
    "        all_tasks.append(task_for_params)\n",
    "        \n",
    "    return all_parameters, all_tasks"
   ]
  },
  {
   "cell_type": "raw",
   "metadata": {
    "deletable": true,
    "editable": true
   },
   "source": [
    "Now we use IPython parallel to get the client and a load balanced view. We must first create a local cluster of N engines by using the Cluster tab in the IPython notebook. Then we create the client, the view and execute our parallel_grid_search function:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/raul/envs/sklearn_book/lib/python2.7/site-packages/sklearn/grid_search.py:148: DeprecationWarning: IterGrid was renamed to ParameterGrid and will be removed in 0.15.\n",
      "  \" removed in 0.15.\", DeprecationWarning)\n"
     ]
    }
   ],
   "source": [
    "from sklearn.svm import SVC\n",
    "from IPython.parallel import Client\n",
    "\n",
    "client = Client()\n",
    "lb_view = client.load_balanced_view()\n",
    "\n",
    "all_parameters, all_tasks = parallel_grid_search(\n",
    "   lb_view, clf, cv_filenames, parameters)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def print_progress(tasks):\n",
    "    progress = np.mean([task.ready() for task_group in tasks\n",
    "                                 for task in task_group])\n",
    "    print \"Tasks completed: {0}%\".format(100 * progress)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Tasks completed: 100.0%\n"
     ]
    }
   ],
   "source": [
    "print_progress(all_tasks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": [
    "def find_bests(all_parameters, all_tasks, n_top=5):\n",
    "    \"\"\"Compute the mean score of the completed tasks\"\"\"\n",
    "    mean_scores = []\n",
    "    \n",
    "    for param, task_group in zip(all_parameters, all_tasks):\n",
    "        scores = [t.get() for t in task_group if t.ready()]\n",
    "        if len(scores) == 0:\n",
    "            continue\n",
    "        mean_scores.append((np.mean(scores), param))\n",
    "                   \n",
    "    return sorted(mean_scores, reverse=True)[:n_top]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[(0.82633333333333336, {'svc__gamma': 0.10000000000000001, 'svc__C': 10.0}), (0.78866666666666674, {'svc__gamma': 1.0, 'svc__C': 10.0}), (0.7466666666666667, {'svc__gamma': 1.0, 'svc__C': 1.0}), (0.23333333333333336, {'svc__gamma': 0.01, 'svc__C': 10.0}), (0.16200000000000001, {'svc__gamma': 0.10000000000000001, 'svc__C': 1.0})]\n"
     ]
    }
   ],
   "source": [
    "print find_bests(all_parameters, all_tasks)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {
    "collapsed": false,
    "deletable": true,
    "editable": true
   },
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 2",
   "language": "python",
   "name": "python2"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 0
}
